package cn.edu.wfit.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
//    @Bean //UserDetailsService 就是获取⽤户信息的服务
//    public UserDetailsService userDetailsService(PasswordEncoder encoder){
//        String encode = encoder.encode("123");
//        boolean matches = encoder.matches("123", encode);
//        System.out.println(matches);
//// 每⼀个UserDetails就代表⼀个⽤户信息,其中包含⽤户的⽤户名和密码以及⻆⾊
//        UserDetails user=
//                User.withDefaultPasswordEncoder().username("wfit").password("123").roles("USER").build(
//                );
//        return new InMemoryUserDetailsManager(user);
//    }
//// 创建⼀个基于内存的⽤户信息管理器作为UserDetailsService
//@Bean //UserDetailsService 就是获取⽤户信息的服务
//public UserDetailsService userDetailsService(DataSource dataSource, PasswordEncoder
//        encoder){
//    JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
//    String encode = encoder.encode("111");
//       System.out.println(encode);
//// 仅⾸次启动的时候创建⼀个新的⽤户⽤于测试
//    if(!manager.userExists("wfit")){
//        manager.createUser(User.withUsername("wfit").password(encoder.encode("1234")).roles("USER").build());
//    }
//    return manager;
//}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
    return http
// 以下是验证请求拦截和放⾏配置
            .authorizeHttpRequests(auth -> {
                auth.antMatchers("/test").permitAll(); // 不拦截指定的⻚⾯
                auth.anyRequest().authenticated(); // 将所有请求全部拦截，⼀律需要验证
            })
// 以下是表单登录相关配置
            .formLogin(conf->{
                conf.successHandler(this::onAuthenticationSuccess);// 登录成功执⾏的⽅法
                conf.failureHandler(this::onAuthenticationFailure);// 登录失败执⾏的⽅法
                conf.loginProcessingUrl("/dologin");// 表单提交的地址，可以⾃定义
                conf.permitAll();//将登录相关的地址放⾏，否则未登录的⽤户连登录界⾯都进不去
//⽤户名和密码的表单字段名称，不过默认就是这个，可以不配置，除⾮有特殊需求
                conf.usernameParameter("username");
                conf.passwordParameter("password");
            }).csrf(AbstractHttpConfigurer::disable).build();
}
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse
            response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("登录成功");
    }
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse
            response, AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("登录失败");
    }
}
